#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
教学评价自动化系统
主入口文件
"""

import os
import sys
import json
import logging
import argparse
import time
import traceback
from typing import Dict

# 导入DrissionPage模式需要的模块
try:
    from drissionpage.login_handler import LoginHandler
    from drissionpage.evaluation_runner import EvaluationRunner
except ImportError:
    # 在其他目录运行时的绝对导入
    from teaching_evaluation.drissionpage.login_handler import LoginHandler
    from teaching_evaluation.drissionpage.evaluation_runner import EvaluationRunner

# 设置日志
logger = logging.getLogger(__name__)

def setup_logger(log_level='INFO'):
    """设置日志系统"""
    numeric_level = getattr(logging, log_level.upper(), None)
    if not isinstance(numeric_level, int):
        raise ValueError(f'Invalid log level: {log_level}')
    
    # 配置根日志
    logging.basicConfig(
        level=numeric_level,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        handlers=[
            logging.FileHandler('evaluation.log', encoding='utf-8'),
            logging.StreamHandler()
        ]
    )
    
    return logging.getLogger(__name__)

# 导入核心模块
from core.page_manager import PageStateMachine
from core.evaluation_handler import EvaluationEngine
from core.data_manager import StateRecorder
from core.interface_parser import InterfaceParser

# 导入工具模块
from utils.screenshot_tool import EvidenceCapturer
from utils.api_client import APIClient
from utils.logger import setup_logger
from utils.retry_mechanism import RetryHandler

def load_config(config_path: str) -> Dict:
    """加载配置文件"""
    with open(config_path, 'r', encoding='utf-8') as f:
        return json.load(f)

def save_config(config_path: str, config: Dict) -> None:
    """保存配置文件"""
    with open(config_path, 'w', encoding='utf-8') as f:
        json.dump(config, f, indent=2, ensure_ascii=False)
    logger.info(f"配置已更新并保存到 {config_path}")

def parse_arguments():
    """解析命令行参数"""
    parser = argparse.ArgumentParser(description='教学评价自动化系统')
    parser.add_argument('--user-list', help='用户账号列表CSV文件路径')
    parser.add_argument('--headless', action='store_true', help='无头模式运行')
    parser.add_argument('--log-level', default='INFO', help='日志级别')
    parser.add_argument('--mode', choices=['selenium', 'drissionpage'], default='selenium', 
                        help='运行模式: selenium(默认)或drissionpage')
    parser.add_argument('--config', help='DrissionPage配置文件路径')
    parser.add_argument('--single-user', help='单用户模式，直接指定用户名')
    parser.add_argument('--password', help='单用户模式下的密码')
    parser.add_argument('--force-eval', action='store_true', help='强制执行评教填写过程')
    parser.add_argument('--interactive', action='store_true', help='交互式输入账号')
    return parser.parse_args()

def process_evaluation(login_handler, args):
    """
    处理评教流程
    
    Args:
        login_handler: 登录处理器对象
        args: 命令行参数
        
    Returns:
        bool: 是否成功完成评教流程
    """
    try:
        # 导入评教点击器
        from drissionpage.evaluation_clicker import EvaluationClicker, run_clicker
        from drissionpage.url_validator import UrlValidator
        
        # 检查评教状态
        logger.info("检查评教状态...")
        validator = UrlValidator(login_handler.page)
        
        # 判断是否需要评教
        needs_eval = validator.validate_url()
        if needs_eval:
            logger.info("发现未完成的评教项，开始执行评教填写过程...")
            
            # 点击评教div
            logger.info("点击评教div...")
            if validator.click_evaluation_div():
                logger.info("成功点击评教div，准备进行评教")
            
            clicker = EvaluationClicker(login_handler.page)
            
            # 添加循环，处理所有待评教的课程
            evaluations_completed = 0
            max_evaluations = 100  # 设置最大处理数量，防止无限循环
            
            while evaluations_completed < max_evaluations:
                # 尝试点击评价按钮
                if clicker.click_evaluation_button():
                    logger.info(f"成功点击第{evaluations_completed+1}门课程的评价按钮，准备填写评教表单...")
                    
                    # 填写评教表单
                    if clicker.fill_evaluation_form():
                        logger.info(f"成功填写第{evaluations_completed+1}门课程的评教表单！")
                        evaluations_completed += 1
                        
                        # 返回评教列表页面
                        try:
                            # 查找并点击"返回"按钮
                            back_button = login_handler.page.ele('xpath://a[contains(text(), "返回")] | //button[contains(text(), "返回")]')
                            if back_button:
                                logger.info("找到返回按钮，点击返回评教列表")
                                back_button.click()
                                time.sleep(0.4)  # 等待页面加载，400毫秒
                            else:
                                # 如果没有找到返回按钮，尝试使用浏览器的后退功能
                                logger.info("未找到返回按钮，使用浏览器后退功能")
                                login_handler.page.back()
                                time.sleep(0.4)  # 等待页面加载，400毫秒
                        except Exception as e:
                            logger.error(f"返回评教列表页面时发生异常: {e}")
                            break
                    else:
                        logger.warning(f"填写第{evaluations_completed+1}门课程的评教表单失败")
                        break
                else:
                    # 如果没有找到更多评价按钮，说明评教已完成
                    logger.info("未找到更多待评价课程，评教任务已全部完成")
                    break
            
            logger.info(f"共完成了 {evaluations_completed} 门课程的评教")
            
            # 完成评教后重新检查评教状态
            logger.info("重新检查评教状态...")
            if validator.validate_url():
                
                logger.info("仍有未完成的评教项，建议再次运行程序")
                process_evaluation(login_handler, args)
                
            else:
                logger.info("所有评教项已全部完成！")
        else:
            logger.info("所有评教项已完成，无需评教")
            
        return True
        
    except Exception as e:
        logger.error(f"执行评教填写过程时发生异常: {e}")
        logger.error(traceback.format_exc())
        return False

def main():
    # 解析命令行参数
    args = parse_arguments()
    
    # 设置日志系统
    logger = setup_logger(log_level=args.log_level)
    logger.info("教学评价自动化系统启动")
    
    # 根据运行模式选择不同的处理逻辑
    if args.mode == 'drissionpage':
        # 使用DrissionPage模式运行
        logger.info("使用DrissionPage模式运行")
        
        # 交互式输入账号
        if args.interactive:
            account = input("请输入账号: ").strip()
            password = f"Gxmu@{account}"
            logger.info(f"账号: {account}, 自动生成密码: {password}")
            
            # 更新配置文件
            config_path = args.config or 'config.json'
            try:
                # 尝试加载配置
                config = load_config(config_path)
                # 更新配置
                config['login']['username'] = account
                config['login']['password'] = password
                # 保存更新后的配置
                save_config(config_path, config)
                
                # 单用户模式使用交互式输入的账号和密码
                args.single_user = account
                args.password = password
                
            except Exception as e:
                logger.error(f"更新配置文件时出错: {e}")
                logger.error(traceback.format_exc())
        
        if args.single_user and args.password:
            # 单用户模式
            logger.info(f"单用户模式，用户名: {args.single_user}")
            login_config = {
                'login_url': 'http://wspj.gxmu.edu.cn/login.jsp',
                'username': args.single_user,
                'password': args.password,
            }
            
            # 创建登录处理器
            login_handler = LoginHandler(login_config)
            
            try:
                # 初始化浏览器
                if not login_handler.initialize():
                    logger.error("浏览器初始化失败，退出程序")
                    return
                
                # 执行登录
                logger.info("开始登录...")
                login_success = login_handler.login()
                
                if login_success:
                    logger.info("登录成功！")
                    
                    # 尝试导航到评教页面
                    if login_handler.navigate_to_evaluation_page():
                        logger.info("已成功导航到评教页面")
                        
                        # 如果设置了强制评教标志，则执行评教流程
                        if args.force_eval:
                            process_evaluation(login_handler, args)
                        
                    else:
                        logger.error("导航到评教页面失败")
                else:
                    logger.error("登录失败")
                    
            except Exception as e:
                logger.error(f"执行过程中发生异常: {e}")
            finally:
                # 在程序退出前保持浏览器窗口打开一段时间
                logger.info("准备关闭浏览器...")
                # 立即关闭浏览器，不再等待
                # 退出登录并关闭浏览器
                login_handler.logout()
        else:
            # 使用完整评教流程
            config_path = args.config
            runner = EvaluationRunner(config_path)
            success = runner.run()
            
            if success:
                logger.info("评教流程全部成功完成！")
            else:
                logger.warning("评教流程可能未完全成功，请检查日志和截图")
    
    else:
        # 使用原有Selenium模式运行
        logger.info("使用Selenium模式运行")
        
        # 加载配置
        try:
            paths_config = load_config('config/paths.json')
            probs_config = load_config('config/probabilities.json')
            
            # 确保必要的目录存在
            os.makedirs(paths_config['state_dir'], exist_ok=True)
            os.makedirs(paths_config['screenshot_dir'], exist_ok=True)
        except Exception as e:
            logger.error(f"配置加载失败: {e}")
            sys.exit(1)
        
        # 读取用户列表
        try:
            if args.user_list:
                with open(args.user_list, 'r', encoding='utf-8') as f:
                    import csv
                    users = list(csv.DictReader(f))
                logger.info(f"成功加载{len(users)}个用户账号")
            else:
                logger.warning("没有指定用户列表，使用默认用户")
                users = [{'id': '20234092832', 'password': 'Gxmu@20234092832'}]
        except Exception as e:
            logger.error(f"用户列表加载失败: {e}")
            sys.exit(1)
        
        # 初始化组件
        api_client = APIClient()
        retry_handler = RetryHandler()
        
        # 主循环: 处理每个用户
        for user in users:
            user_id = user['id']
            logger.info(f"开始处理用户: {user_id}")
            
            # 创建用户专属目录
            user_screenshot_dir = os.path.join(paths_config['screenshot_dir'], user_id)
            os.makedirs(user_screenshot_dir, exist_ok=True)
            
            # 初始化状态记录器
            state_recorder = StateRecorder(paths_config['state_dir'])
            user_state = state_recorder.load_state(user_id)
            
            # 初始化截图工具
            evidence_capturer = EvidenceCapturer(user_screenshot_dir)
            
            # 初始化浏览器控制器
            # 这里实际实现时需要根据具体浏览器自动化库调整
            try:
                # 初始化页面控制器和评价引擎
                page_manager = PageStateMachine()
                evaluation_engine = EvaluationEngine(api_client, retry_handler, probs_config)
                interface_parser = InterfaceParser()
                
                # 主工作流循环
                while user_state.get('has_pending_courses', True):
                    # 检测当前页面类型
                    current_page = page_manager.detect_current_page()
                    logger.info(f"当前页面类型: {current_page}")
                    
                    # 根据页面类型分发处理
                    if current_page == "选择题页":
                        result = evaluation_engine.handle_choice_question()
                        state_recorder.save_state(user_id, {"action": "选择题完成", "result": result})
                        evidence_capturer.capture_sequence(user_id, "choice_completed")
                        
                    elif current_page == "填空题页":
                        result = evaluation_engine.handle_text_question()
                        state_recorder.save_state(user_id, {"action": "填空题完成", "result": result})
                        evidence_capturer.capture_sequence(user_id, "text_completed")
                        
                    elif current_page == "完成页":
                        user_state['has_pending_courses'] = False
                        state_recorder.save_state(user_id, {"action": "评教完成"})
                        evidence_capturer.capture_sequence(user_id, "evaluation_completed")
                        
                    # 执行界面跳转
                    page_manager.navigate_to_next(current_page)
                
                logger.info(f"用户 {user_id} 评教任务全部完成")
                
            except Exception as e:
                logger.error(f"处理用户 {user_id} 时发生异常: {e}")
                # 捕获异常情况的截图
                evidence_capturer.capture_sequence(user_id, "exception")
                continue
            finally:
                # 清理资源
                logger.info(f"正在清理用户 {user_id} 的会话资源")
        
        logger.info("教学评价自动化系统任务全部完成")


if __name__ == "__main__":
    main() 